<template>
	<view class="flex flex-col relative">
		<tm-sheet v-if="!props.hideTool" :shadow="0" :round="0" :height="88" :margin="[0, 0]" :padding="[0, 0]" _class="flex flex-col">
			<view class="flex flex-row flex-row-center-center" style="height: 88rpx">
				<view @click.stop="prevYear" class="px-16">
					<tm-icon :userInteractionEnabled="false" :font-size="22" name="tmicon-angle-double-left"></tm-icon>
				</view>
				<view @click.stop="prevMonth" class="px-16">
					<tm-icon :userInteractionEnabled="false" :font-size="22" name="tmicon-angle-left"></tm-icon>
				</view>
				<view class="px-12">
					<tm-text :userInteractionEnabled="false" _class="text-weight-b" :font-size="32" :label="_nowDate"></tm-text>
				</view>
				<view @click.stop="nextMonth" class="px-16">
					<tm-icon :userInteractionEnabled="false" :font-size="22" name="tmicon-angle-right"></tm-icon>
				</view>
				<view @click.stop="nextYear" class="px-16">
					<tm-icon :userInteractionEnabled="false" :font-size="22" name="tmicon-angle-double-right"></tm-icon>
				</view>
			</view>
			<view
				@click="nowWeekClick"
				class="absolute t-0 r--6 zIndex-10 round-12 py-4 flex flex-row flex-row-center-center"
				style="width: 90rpx; height: 88rpx"
			>
				<tm-text :userInteractionEnabled="false" color="grey" _class="text-align-center" :font-size="28" label="本周"></tm-text>
			</view>
		</tm-sheet>

		<view class="flex flex-row flex-row-center-center py-12" :style="[{ height: '74rpx' }]">
			<view class="flex-1 flex-center" v-for="(item, index) in weekStr" :key="index">
				<view style="width: 62rpx" class="flex-center flex-col">
					<tm-text :font-size="24" :label="item"></tm-text>
				</view>
			</view>
		</view>
		<view class="flex flex-col">
			<view class="flex flex-row flex-row-center-center" :style="[{ height: '74rpx' }]" v-for="(item, index) in _dataWeek" :key="index">
				<view :class="['opacity-5']" class="flex-1 flex-center">
					<view style="width: 62rpx" class="flex-center flex-col">
						<tm-text :font-size="24" :label="item"></tm-text>
					</view>
				</view>
				<tm-sheet
					no-level
					@click="clickWeek(item)"
					:height="66"
					:shadow="0"
					:round="10"
					_class="flex-row"
					class="flex-6"
					paren-class="flex-6"
					:text="_weekNum == item"
					:color="_weekNum == item ? _color : 'grey-4'"
					:margin="[0, 4]"
					:padding="[0, 0]"
				>
					<view
						:userInteractionEnabled="false"
						style="width: 62rpx"
						:class="[item2.isNowIn ? '' : 'opacity-5']"
						class="flex-1 flex-center"
						v-for="(item2, index2) in _data[index]"
						:key="index2"
					>
						<view style="width: 62rpx" class="flex-center flex-col" :style="[{ opacity: item2.isVaild ? '0.3' : '1' }]">
							<tm-text :font-size="28" :label="item2.date"></tm-text>
						</view>
					</view>
				</tm-sheet>
			</view>
		</view>

		<tm-button
			v-if="!props.hideButton"
			:linear="props.linear"
			:linear-deep="props.linearDeep"
			:color="props.color"
			@click="confirm"
			block
			label="确认"
			:margin="[0, 16]"
		></tm-button>
	</view>
</template>

<script lang="ts" setup>
/**
 * 按周选择的日历
 * @description 可以按月，按日，按周，按季度显示
 */
import { computed, ref, Ref, watch, PropType } from 'vue'
import tmSheet from '../tm-sheet/tm-sheet.vue'
import tmIcon from '../tm-icon/tm-icon.vue'
import tmText from '../tm-text/tm-text.vue'
import tmButton from '../tm-button/tm-button.vue'
import * as dayjs from '../../tool/dayjs/esm/index'
import isoWeek from '../../tool/dayjs/esm/plugin/isoWeek/index'
import isSameOrBefore from '../../tool/dayjs/esm/plugin/isSameOrBefore/index'
import isSameOrAfter from '../../tool/dayjs/esm/plugin/isSameOrAfter/index'
import isBetween from '../../tool/dayjs/esm/plugin/isBetween/index'
import { weekItem } from './interface'
import { useTmpiniaStore } from '../../tool/lib/tmpinia'
const store = useTmpiniaStore()
/**
 * 事件说明
 * v-model 绑定当前的周次时间开始和结束时间。
 * confirm 当点击确认时触发
 * click-week 点击时期上的周次时触发。
 * change 当切换年或者月的时候触发。
 */
const emits = defineEmits(['update:modelValue', 'confirm', 'click-week', 'change'])
const props = defineProps({
	followTheme: {
		type: Boolean,
		default: true
	},
	//默认显示的日期，自动转换为当前的周次。只会取第一个时间判断当前周次。
	defaultValue: {
		type: Array as PropType<Array<String | Number | Date>>,
		default: () => []
	},
	//当前的周时间段，本年度周一至周日的时间范围段。
	modelValue: {
		type: Array as PropType<Array<String | Number | Date>>,
		default: () => []
	},
	color: {
		type: String,
		default: 'primary'
	},
	linear: {
		type: String as PropType<'left' | 'right' | 'bottom' | 'top' | ''>,
		default: ''
	},
	linearDeep: {
		type: String as PropType<'accent' | 'dark' | 'light'>,
		default: 'light'
	},
	//指的是：有效的可选时间，小于此时间，不允许选中。
	start: {
		type: [String, Number, Date],
		default: ''
	},
	//指的是：有效的可选时间，大于此时间，不允许选中。
	end: {
		type: [String, Number, Date],
		default: ''
	},
	//隐藏头部操作栏
	hideTool: {
		type: Boolean,
		default: false
	},
	//隐藏底部确认按钮
	hideButton: {
		type: Boolean,
		default: false
	}
})
const _color = computed(() => {
	if (props.followTheme && store.tmStore.color) return store.tmStore.color
	return props.color
})
const DayJs = dayjs.default

DayJs.extend(isoWeek)
DayJs.extend(isSameOrBefore)
DayJs.extend(isSameOrAfter)
DayJs.extend(isBetween)

//当前的时间
const _value = ref(DayJs(props.defaultValue[0]).isValid() ? DayJs(props.defaultValue[0]) : DayJs())
//当前的周次。
const _weekNum = ref(getNowWeek(_value.value))
const weekStr = ['周次', '一', '二', '三', '四', '五', '六', '日']
const _data: Ref<Array<Array<weekItem>>> = ref([])
const _dataWeek: Ref<Array<number>> = ref([]) //本月的周次。
const _start_date = computed(() => {
	let isv = DayJs(props.start).isValid()
	return isv ? DayJs(props.start) : DayJs('1980-1-1')
})
const _end_date = computed(() => {
	let isv = DayJs(props.end).isValid()
	return isv ? DayJs(props.end) : DayJs('2450-1-1')
})

//当前的年月日期。
const _nowDate = computed(() => {
	return _value.value.format('YYYY-MM')
})
_data.value = getWeekOfMonthArray()

watch(
	() => props.modelValue,
	() => {
		if (!Array.isArray(props.modelValue)) return
		let date_str = props.modelValue[0] ?? ''
		_value.value = DayJs(date_str).isValid() ? DayJs(date_str) : DayJs()
		_weekNum.value = getNowWeek(_value.value)
		_data.value = getWeekOfMonthArray()
	},
	{ deep: true }
)
//获取当前周次。根据当前日期。
function getNowWeek(str: string | dayjs.Dayjs | number | Date = '') {
	if (DayJs(str).isValid()) {
		return DayJs(str).isoWeek()
	} else {
		return DayJs().isoWeek()
	}
}
function nowWeekClick() {
	_value.value = DayJs()
	_data.value = getWeekOfMonthArray()
	let wk = getNowWeek(_value.value)
	if (!canSelected(wk)) {
		uni.showToast({ title: '无法选中', icon: 'none' })
		return
	}
	_weekNum.value = wk

	updateTimes()
}
function clickWeek(wk: number) {
	if (!canSelected(wk)) {
		uni.showToast({ title: '无法选中', icon: 'none' })
		return
	}
	_weekNum.value = wk
	updateTimes()
}
function canSelected(num: number) {
	// 能否选中周次。
	let index = _dataWeek.value.findIndex((el) => el == num)
	let item = _data.value[index]
	let ar = item.filter((el) => !el.isVaild)

	return ar.length > 0
}
function nextYear() {
	_value.value = _value.value.add(1, 'year')
	_data.value = getWeekOfMonthArray()
	emits('change', _value.value.format('YYYY/MM/DD'))
}
function nextMonth() {
	_value.value = _value.value.add(1, 'month')
	_data.value = getWeekOfMonthArray()
	emits('change', _value.value.format('YYYY/MM/DD'))
}
function prevMonth() {
	_value.value = _value.value.subtract(1, 'month')
	_data.value = getWeekOfMonthArray()
	emits('change', _value.value.format('YYYY/MM/DD'))
}
function prevYear() {
	_value.value = _value.value.subtract(1, 'year')
	_data.value = getWeekOfMonthArray()
	emits('change', _value.value.format('YYYY/MM/DD'))
}

//设置当前选中的日期范围，参数为周次中的某一个日期即可，会自动转换成以该日期为周的范围段。
function setDefault(data: Array<String | Number | Date> = []) {
	let date_str = data[0]
	_value.value = DayJs(date_str).isValid() ? DayJs(date_str) : DayJs()
	_weekNum.value = getNowWeek(_value.value)
	_data.value = getWeekOfMonthArray()
}

//获取本月按周分组的时间段。
function getWeekOfMonthArray() {
	let nowMonth: dayjs.Dayjs = DayJs(_value.value)
	let startStatickDay = nowMonth.startOf('month').format('YYYY/MM/DD')
	let endStatickDay = nowMonth.endOf('month').format('YYYY/MM/DD')
	let startd = DayJs(startStatickDay)

	let arOfmonth: Array<number> = [] //本月的周次。
	let ar: Array<weekItem> = []
	while (startd.isSameOrBefore(endStatickDay)) {
		ar.push({
			dateStr: startd.format('YYYY/MM/DD'),
			date: startd.date() < 10 ? '0' + startd.date() : startd.date(),
			week: startd.isoWeek(),
			day: startd.isoWeekday(),
			isNowIn: isInNowMonth(nowMonth, startd),
			isVaild: !startd.isBetween(_start_date.value, _end_date.value, 'day', '[]')
		})
		arOfmonth.push(startd.isoWeek())
		startd = startd.add(1, 'day')
	}
	arOfmonth = [...new Set(arOfmonth)]
	_dataWeek.value = arOfmonth
	let dArray: Array<Array<weekItem>> = []
	let index = 0
	dArray.push([])
	ar.forEach((el) => {
		if (el.week == arOfmonth[index]) {
			dArray[index].push(el)
		} else {
			index += 1
			dArray.push([])
			dArray[index].push(el)
		}
	})
	//补齐前尾的7天时间。
	if (dArray[0].length !== 7) {
		let item = dArray[0][dArray[0].length - 1]
		let start_of = DayJs(item.dateStr).isoWeek(item.week).subtract(6, 'day')
		let end_of = DayJs(item.dateStr).isoWeek(item.week)
		let pr = []
		let startd = DayJs(start_of)
		while (startd.isSameOrBefore(end_of)) {
			pr.push({
				dateStr: startd.format('YYYY/MM/DD'),
				date: startd.date() < 10 ? '0' + startd.date() : startd.date(),
				week: startd.isoWeek(),
				day: startd.isoWeekday(),
				isNowIn: isInNowMonth(nowMonth, startd),
				isVaild: !startd.isBetween(_start_date.value, _end_date.value, 'day', '[]')
			})
			startd = startd.add(1, 'day')
		}
		dArray[0] = pr
	}
	if (dArray[dArray.length - 1].length !== 7) {
		let item = dArray[dArray.length - 1][0]

		let start_of = DayJs(item.dateStr).isoWeek(item.week)
		let end_of = DayJs(item.dateStr).isoWeek(item.week).add(6, 'day')
		let pr = []
		let startd = DayJs(start_of)
		while (startd.isSameOrBefore(end_of)) {
			pr.push({
				dateStr: startd.format('YYYY/MM/DD'),
				date: startd.date() < 10 ? '0' + startd.date() : startd.date(),
				week: startd.isoWeek(),
				day: startd.isoWeekday(),
				isNowIn: isInNowMonth(nowMonth, startd),
				isVaild: !startd.isBetween(_start_date.value, _end_date.value, 'day', '[]')
			})
			startd = startd.add(1, 'day')
		}
		dArray[dArray.length - 1] = pr
	}
	return dArray
}
// 检测now日期是否在某个日期的月份中.
function isInNowMonth(date: string | dayjs.Dayjs | number = '', now: string | dayjs.Dayjs | number = '') {
	let startStatickDay = DayJs(date).startOf('month').format('YYYY/MM/DD')
	let endStatickDay = DayJs(date).endOf('month').format('YYYY/MM/DD')
	return DayJs(now).isBetween(startStatickDay, endStatickDay, 'day', '[]')
}

//update
function updateTimes() {
	let index = _dataWeek.value.findIndex((el) => el == _weekNum.value)
	let item = _data.value[index]
	let start = item[0].dateStr
	let end = item[item.length - 1].dateStr
	emits('click-week', [start, end])
}
function confirm() {
	let index = _dataWeek.value.findIndex((el) => el == _weekNum.value)
	let item = [..._data.value[index]]
	let start = item[0].dateStr
	// 最开始的日期如果在start后就可以直接读取
	for (let i = 0; i < item.length; i++) {
		if (DayJs(item[i].dateStr).isSameOrAfter(props.start, 'date')) {
			start = item[i].dateStr
			break
		}
	}
	let end = item[item.length - 1].dateStr
	item = item.reverse()
	console.log(item)
	for (let i = 0; i < item.length; i++) {
		if (DayJs(item[i].dateStr).isSameOrBefore(props.end, 'date')) {
			end = item[i].dateStr
			break
		}
	}

	emits('update:modelValue', [start, end])
	emits('confirm', [start, end])
}
defineExpose({
	setDefault: setDefault,
	nextYear: nextYear,
	nextMonth: nextMonth,
	prevYear: prevYear,
	prevMonth: prevMonth
})
</script>

<style></style>
